<!--
 * @Author: Zhang Yingying
 * @Date: 2020-10-21 17:03:59
 * @LastEditors: Zhang Yingying
 * @LastEditTime: 2020-12-14 22:06:33
-->
<script>
import Vue from "vue";
import Component from "vue-class-component";
import { Prop } from "vue-property-decorator";
import FormControl from "./form-control.vue";
import { Row, Col } from "../config";
import { isObj } from "../utils";

const layouts = {
  [Col](h, currentItem) {
    const { style, ...config } = currentItem;
    const child = renderChildren.apply(this, arguments);
    let labelWidth = !Number.isNaN(+config.labelWidth)
      ? `${config.labelWidth}px`
      : null;
    if (config.showLabel === false) labelWidth = "0";
    return (
      <el-col span={config.span}>
        <el-form-item
          prop={config.prop}
          label-width={labelWidth}
          rules={config.rules}
          label={config.showLabel ? config.label : ""}
        >
          <form-control
            {...{
              props: {
                ...config,
                value: this.value
              },
              attrs: {
                ...config
              },
              style: {
                ...style
              },
              on: {
                ...currentItem.events,
                input: val => {
                  this.$emit("input", val);
                }
              }
            }}
            key={config.prop}
          >
            {child}
          </form-control>
        </el-form-item>
      </el-col>
    );
  },
  [Row](h, currentItem) {
    const { style, ...config } = currentItem;
    let child = renderChildren.apply(this, arguments);
    if (currentItem.type === "flex") {
      child = (
        <el-row
          type={currentItem.type}
          justify={currentItem.justify}
          align={currentItem.align}
        >
          {child}
        </el-row>
      );
    }
    return (
      <el-col span={config.span} style={style}>
        <el-row gutter={config.gutter}>{child}</el-row>
      </el-col>
    );
  },
  raw(h, currentItem) {
    const { style, ...config } = currentItem;
    const child = renderChildren.apply(this, arguments);
    return (
      <form-control
        {...{
          props: {
            ...currentItem,
            value: this.value
          },
          attrs: {
            ...currentItem
          },
          style: {
            ...style
          },
          on: {
            ...currentItem.events,
            input: val => {
              this.$emit("input", val);
            }
          }
        }}
        key={config.prop}
      >
        {child}
      </form-control>
    );
  }
};

function renderChildren(h, currentItem) {
  const config = currentItem;
  if (!Array.isArray(config.children) || isObj(config.children)) {
    return null;
  }

  var arr = Array.isArray(config.children)
    ? config.children
    : Object.values(config.children);

  return arr.map(el => {
    const layout = layouts[el.layout];
    if (layout) {
      return layout.call(this, h, el);
    }
    return layoutIsNotFound.call(this);
  });
}

function layoutIsNotFound() {
  throw new Error(`没有与${this.item.layout}匹配的布局组件`);
}

@Component({
  name: "FormItem",
  components: {
    FormControl
  }
})
export default class FormItem extends Vue {
  @Prop({
    type: Object,
    required: true
  })
  item;

  @Prop({
    required: false
  })
  value;

  /**
   * 外部传入的插槽
   */
  @Prop({
    required: false
  })
  sloter;

  render(h) {
    if (typeof this.sloter === "function") {
      return this.sloter({ ...this.item, value: this.value });
    }
    const layout = layouts[this.item.layout];
    if (layout) {
      return layout.call(this, h, this.item);
    }
    return layoutIsNotFound.call(this);
  }
}
</script>
